using Commons.Collections;
using System;
using System.Collections.Generic;

namespace Commons.Models.Capabilities
{
	[Serializable]
	public class CapableDelegate<E> : ICapable where E : ICapable
	{
		private E delegator;
		private TypeDictionary<ICapability> capabilities;

		public CapableDelegate (E delegator)
		{
			this.delegator = delegator;
			this.capabilities = new TypeDictionary<ICapability>();
		}

		public bool HasCapability<T> () where T : ICapability
		{
			return capabilities.Get<T>() != null;
		}

		public bool HasCapability (Type type)
		{
			return capabilities.Get (type) != null;
		}

		public T GetCapability<T> () where T : ICapability
		{
			ICapability capability = capabilities.Get<T>();
			if (capability == null)
			{
				throw new ArgumentException(delegator.ToString() + " does not have the requested capability " + typeof(T).Name);
			}
			return (T) capability;
		}

		public object GetCapability(Type type) 
		{
			ICapability capability = capabilities.Get(type) as ICapability;
			if (capability == null)
			{
				throw new ArgumentException(delegator.ToString() + " does not have the requested capability " + type.Name);
			}
			return capability;
		}

		public void AddCapability (ICapability capability)
		{
			capabilities.Add (capability);
			if (capability is ICapableAware<E>)
			{
				((ICapableAware<E>)capability).SetCapable (this.delegator);
			}
		}

		public IEnumerable<ICapability> GetCapabilities ()
		{
			return capabilities.Values;
		}
	}
}
